﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Security.Principal;

namespace ALDIOrganizer
{       
    [Serializable]
    public sealed class User
    {       
        /// <summary>
        /// Creates a new user with specified criteria
        /// </summary>
        /// <param Name="EmployeeID">_employee id related to emps_from_database primary key in CurrentFile. optional (-1 = not applied)</param>
        /// <param Name="_login">string the user will be giving as _login on the logging form. no white spaces!</param>
        /// <param Name="password">string containing his password</param>
        internal User(
            int pEmpID,
            string pLogin,
            byte[] pPasswordHash,
            UserPrivilege pPrivileges)
        {
            if (pLogin != pLogin.Trim())
            {
                throw new ArgumentException(
                    "User login cannot contain white spaces!");
            }
            Login = pLogin;
            ID = pEmpID;           
            _passwordHash = pPasswordHash;
            var identity = new GenericIdentity(Login);
            _privileges = pPrivileges;
            _principal = new GenericPrincipal(
                identity,
                _privileges.GetRoles());                
        }

        public static byte[] ComputeHash(string pPassword)
        {
            var passwordAsBytes = Encoding.ASCII.GetBytes(pPassword);
            return new MD5CryptoServiceProvider().ComputeHash(passwordAsBytes);
        }

        public long ID { get; private set; }

        /// <summary>
        /// Is employee of
        /// </summary>
        public bool NotAnEmployee
        {
            get
            {
                if (ID == -1)
                {
                    return true;
                }
                return !SQLiteAccess.GetEmployeeIDs(-1).Contains(ID);
            }
        }

        public string Login { get; private set; }

        private readonly byte[] _passwordHash;
        public byte[] GetPasswordHash
        {
            get
            {
                return _passwordHash;
            }
        }
        
        public GenericPrincipal GetPrincipal
        {
            get
            {
                return _principal;
            }
        }

        private readonly GenericPrincipal _principal;
        private readonly UserPrivilege _privileges;

        #region checking privileges
        public bool CanEditRota(DateTime pMonday)
        {
            var isItPassed = (pMonday < DateTime.Now.MondayOfThatWeek());
            return isItPassed ? // if the Monday belong to a week in the past...
                ((_privileges & UserPrivilege.EditingPastRotas) != 0) // check if the user can edit past rotas
                : (((_privileges & (UserPrivilege.EditingRotas | // otherwise, check if the user can edit rotas
                UserPrivilege.EditingPastRotas)) != 0)); // ...or past rotas!            
        }

        public bool CanDeleteStaff
        {
            get
            {
                return (_privileges & UserPrivilege.DeletingStaff) != 0;
            }
        }

        public bool CanEditContracts
        {
            get
            {
                return (_privileges & UserPrivilege.EditingContracts) != 0;
            }
        }

        public bool CanEditHolidays
        {
            get
            {
                return ((_privileges & UserPrivilege.EditingHolidays) != 0);
            }
        }

        public bool CanEditPastHolidays
        {
            get
            {
                return ((_privileges & UserPrivilege.EditingPastHolidays) != 0);
            }
        }

        public bool CanEditRequests
        {
            get
            {
                return ((_privileges & UserPrivilege.EditingRequests) != 0);
            }
        }

        public bool CanEditStaff
        {
            get
            {
                return ((_privileges & UserPrivilege.EditingStaff) != 0);
            }
        }

        public bool CanEditTemplates
        {
            get
            {
                return ((_privileges & UserPrivilege.EditingTemplates) != 0);
            }
        }

        /// <summary>
        /// Allowed to see requests (and to AddAnotherRowString pending requests, but only for one'pShift own)
        /// </summary>
        /// <remarks>
        /// If ViewingRequests privilege is not combined with EditingRequests, user can see
        /// other people'pShift requests, but not the comments to them (comments presumably contain
        /// the reason why somebody asked for a Day off etc.; it is assumed that this information
        /// is for eyes of the manager - not every fellow employee needs to know that.
        /// 
        /// One can still ...
        /// 
        /// This behaviour is ... 
        /// </remarks>
        public bool CanViewRequests
        {
            get
            {
                return ((_privileges & UserPrivilege.ViewingRequests) != 0);
            }
        }

        public bool CanViewStaff
        {
            get
            {
                return ((_privileges & UserPrivilege.ViewingStaff) != 0);
            }
        }

        /// <summary>
        /// User can save data files
        /// </summary>
        public bool CanSaveDatafiles
        {
            get
            {
                return this.CanEditTemplates |
                    ((this._privileges & UserPrivilege.EditingPastRotas) != 0) |
                    ((this._privileges & UserPrivilege.EditingRotas) != 0);
            }
        }        

        #endregion

        public override string ToString()
        {
            var result = String.Empty;
            if (!NotAnEmployee)
            {
                result += SQLiteAccess.GetEmployeeFullName(ID);
            }
            else
            {
                result += Login;
            }
            return result;
        }

        /// <summary>
        /// Return all existing UserPrivileges combined. 100% level.
        /// </summary>        
        public static UserPrivilege FullPrivileges
        {
            get
            {
                return (UserPrivilege.DeletingStaff |
                    UserPrivilege.EditingContracts |
                    UserPrivilege.EditingHolidays |
                    UserPrivilege.EditingPastHolidays |
                    UserPrivilege.EditingPastRotas |
                    UserPrivilege.EditingRequests |
                    UserPrivilege.EditingRotas |
                    UserPrivilege.EditingStaff |
                    UserPrivilege.EditingTemplates |
                    UserPrivilege.ViewingRequests |
                    UserPrivilege.ViewingStaff);
            }
        }
    }    
}
